package interpreter

import (
	"bytes"
	"fmt"
	"hash/fnv"
	"jsengine/ast"
	"strings"
)

// ObjectType 是对象类型的标识符
type ObjectType string

// 定义所有对象类型
const (
	INTEGER_OBJ      = "INTEGER"
	FLOAT_OBJ        = "FLOAT"
	BOOLEAN_OBJ      = "BOOLEAN"
	NULL_OBJ         = "NULL"
	UNDEFINED_OBJ    = "UNDEFINED"
	RETURN_VALUE_OBJ = "RETURN_VALUE"
	ERROR_OBJ        = "ERROR"
	FUNCTION_OBJ     = "FUNCTION"
	STRING_OBJ       = "STRING"
	BUILTIN_OBJ      = "BUILTIN"
	ARRAY_OBJ        = "ARRAY"
	OBJECT_OBJ       = "OBJECT"
	BREAK_OBJ        = "BREAK"
	CONTINUE_OBJ     = "CONTINUE"
	CLASS_OBJ        = "CLASS"
	CLASS_INST_OBJ   = "CLASS_INSTANCE"
	SUPER_REF_OBJ    = "SUPER_REFERENCE"
)

// Object 接口表示所有对象
type Object interface {
	Type() ObjectType
	Inspect() string
}

// Integer 表示整数对象
type Integer struct {
	Value int64
}

func (i *Integer) Type() ObjectType { return INTEGER_OBJ }
func (i *Integer) Inspect() string  { return fmt.Sprintf("%d", i.Value) }

// Float 表示浮点数对象
type Float struct {
	Value float64
}

func (f *Float) Type() ObjectType { return FLOAT_OBJ }
func (f *Float) Inspect() string  { return fmt.Sprintf("%g", f.Value) }

// Boolean 表示布尔值对象
type Boolean struct {
	Value bool
}

func (b *Boolean) Type() ObjectType { return BOOLEAN_OBJ }
func (b *Boolean) Inspect() string  { return fmt.Sprintf("%t", b.Value) }

// Null 表示null对象
type Null struct{}

func (n *Null) Type() ObjectType { return NULL_OBJ }
func (n *Null) Inspect() string  { return "null" }

// Undefined 表示undefined对象
type Undefined struct{}

func (u *Undefined) Type() ObjectType { return UNDEFINED_OBJ }
func (u *Undefined) Inspect() string  { return "undefined" }

// ReturnValue 表示返回值
type ReturnValue struct {
	Value Object
}

func (rv *ReturnValue) Type() ObjectType { return RETURN_VALUE_OBJ }
func (rv *ReturnValue) Inspect() string  { return rv.Value.Inspect() }

// Error 表示错误
type Error struct {
	Message string
}

func (e *Error) Type() ObjectType { return ERROR_OBJ }
func (e *Error) Inspect() string  { return "Error: " + e.Message }

// Function 表示函数对象
type Function struct {
	Parameters         []*ast.Identifier
	Body               *ast.BlockStatement
	Env                *Environment
	Name               string
	IsArrow            bool   // 是否是箭头函数
	IsSingleParamArrow bool   // 是否是单参数箭头函数
	SingleParamName    string // 单参数箭头函数的参数名
}

func (f *Function) Type() ObjectType { return FUNCTION_OBJ }
func (f *Function) Inspect() string {
	var out bytes.Buffer

	params := []string{}
	for _, p := range f.Parameters {
		params = append(params, p.String())
	}

	out.WriteString("function")
	if f.Name != "" {
		out.WriteString(" " + f.Name)
	}
	out.WriteString("(")
	out.WriteString(strings.Join(params, ", "))
	out.WriteString(") {\n")
	out.WriteString(f.Body.String())
	out.WriteString("\n}")

	return out.String()
}

// String 表示字符串对象
type String struct {
	Value string
}

func (s *String) Type() ObjectType { return STRING_OBJ }
func (s *String) Inspect() string  { return s.Value }

// BuiltinFunction 是内置函数的类型定义
type BuiltinFunction func(args ...Object) Object

// Builtin 表示内置函数对象
type Builtin struct {
	Fn BuiltinFunction
}

func (b *Builtin) Type() ObjectType { return BUILTIN_OBJ }
func (b *Builtin) Inspect() string  { return "builtin function" }

// Array 表示数组对象
type Array struct {
	Elements []Object
	Methods  map[string]Object
}

func (ao *Array) Type() ObjectType { return ARRAY_OBJ }
func (ao *Array) Inspect() string {
	var out bytes.Buffer

	elements := []string{}
	for _, e := range ao.Elements {
		elements = append(elements, e.Inspect())
	}

	out.WriteString("[")
	out.WriteString(strings.Join(elements, ", "))
	out.WriteString("]")

	return out.String()
}

// HashKey 表示哈希键
type HashKey struct {
	Type  ObjectType
	Value uint64
}

// Hashable 接口表示可以作为哈希键的对象
type Hashable interface {
	HashKey() HashKey
}

// HashPair 表示哈希键值对
type HashPair struct {
	Key   Object
	Value Object
}

// Hash 表示哈希对象（JavaScript中的对象）
type Hash struct {
	Pairs     map[HashKey]HashPair
	Prototype *Hash
	Methods   map[string]Object
}

func (h *Hash) Type() ObjectType { return OBJECT_OBJ }
func (h *Hash) Inspect() string {
	var out bytes.Buffer

	pairs := []string{}
	// 忽略系统内置的console方法
	systemBuiltins := map[string]bool{
		"log": true, "error": true, "warn": true,
		"info": true, "debug": true, "trace": true,
	}

	for _, pair := range h.Pairs {
		// 跳过console对象的内置方法
		if strKey, ok := pair.Key.(*String); ok {
			if systemBuiltins[strKey.Value] && IsBuiltin(pair.Value) {
				continue
			}
		}

		pairs = append(pairs, fmt.Sprintf("%s: %s",
			pair.Key.Inspect(), pair.Value.Inspect()))
	}

	out.WriteString("{")
	out.WriteString(strings.Join(pairs, ", "))
	out.WriteString("}")

	return out.String()
}

// 为基本类型实现Hashable接口

func (b *Boolean) HashKey() HashKey {
	var value uint64

	if b.Value {
		value = 1
	} else {
		value = 0
	}

	return HashKey{Type: b.Type(), Value: value}
}

func (i *Integer) HashKey() HashKey {
	return HashKey{Type: i.Type(), Value: uint64(i.Value)}
}

func (s *String) HashKey() HashKey {
	h := fnv.New64a()
	h.Write([]byte(s.Value))

	return HashKey{Type: s.Type(), Value: h.Sum64()}
}

// Break 表示break语句的结果
type Break struct{}

func (b *Break) Type() ObjectType { return BREAK_OBJ }
func (b *Break) Inspect() string  { return "break" }

// Continue 表示continue语句的结果
type Continue struct{}

func (c *Continue) Type() ObjectType { return CONTINUE_OBJ }
func (c *Continue) Inspect() string  { return "continue" }

// 为Array和Hash实现方法调用
type ObjectWithMethods interface {
	GetMethod(name string) (Object, bool)
}

func (ao *Array) GetMethod(name string) (Object, bool) {
	method, ok := ao.Methods[name]
	return method, ok
}

func (h *Hash) GetMethod(name string) (Object, bool) {
	// 先查找自身方法
	method, ok := h.Methods[name]
	if ok {
		return method, true
	}

	// 如果没有找到，查找原型链
	if h.Prototype != nil {
		return h.Prototype.GetMethod(name)
	}

	return nil, false
}

// Class 表示类对象
type Class struct {
	Name        string
	Properties  map[string]Object
	Methods     map[string]Object
	Constructor *Function
	Prototype   *Hash
}

func (c *Class) Type() ObjectType { return CLASS_OBJ }
func (c *Class) Inspect() string {
	return fmt.Sprintf("class %s {...}", c.Name)
}
func (c *Class) String() string {
	return c.Inspect()
}

// GetMethod 实现ObjectWithMethods接口，支持获取静态方法
func (c *Class) GetMethod(name string) (Object, bool) {
	method, ok := c.Methods[name]
	return method, ok
}

// ClassInstance 表示类实例
type ClassInstance struct {
	Class      *Class
	Properties map[HashKey]HashPair
}

func (ci *ClassInstance) Type() ObjectType { return CLASS_INST_OBJ }
func (ci *ClassInstance) Inspect() string {
	return fmt.Sprintf("%s instance", ci.Class.Name)
}
func (ci *ClassInstance) String() string {
	return ci.Inspect()
}

// GetMethod 实现ObjectWithMethods接口，支持获取实例方法
func (ci *ClassInstance) GetMethod(name string) (Object, bool) {
	// 先检查类的实例方法
	if ci.Class != nil && ci.Class.Prototype != nil {
		// 直接返回方法，不需要展开，让evalCallExpression处理
		method, ok := ci.Class.Prototype.Methods[name]
		if ok {
			return method, true
		}

		// 原型链查找
		current := ci.Class.Prototype.Prototype
		for current != nil {
			if method, ok := current.Methods[name]; ok {
				return method, true
			}
			current = current.Prototype
		}
	}

	return nil, false
}

// IsBuiltin 检查对象是否为内置函数
func IsBuiltin(obj Object) bool {
	_, ok := obj.(*Builtin)
	return ok
}

// NewHash 创建新的Hash对象
func NewHash() *Hash {
	return &Hash{
		Pairs:     make(map[HashKey]HashPair),
		Methods:   make(map[string]Object),
		Prototype: nil,
	}
}

// SuperReference 表示super引用
type SuperReference struct {
	Instance *ClassInstance // 当前实例
	Super    *Hash          // 父类原型
}

func (sr *SuperReference) Type() ObjectType { return SUPER_REF_OBJ }
func (sr *SuperReference) Inspect() string  { return "super" }

// GetMethod 获取父类方法
func (sr *SuperReference) GetMethod(name string) (Object, bool) {
	if sr.Super != nil {
		// 从父类原型中查找方法
		method, ok := sr.Super.Methods[name]
		if ok {
			return method, true
		}

		// 继续在原型链上查找
		if sr.Super.Prototype != nil {
			proto := sr.Super.Prototype
			for proto != nil {
				method, ok := proto.Methods[name]
				if ok {
					return method, true
				}
				proto = proto.Prototype
			}
		}
	}
	return nil, false
}
